﻿#ifndef __INC_QG_D11_DEV_H__
#define __INC_QG_D11_DEV_H__

#ifdef _MSC_VER
#pragma once
#endif

#include "qg/qgasv.h"

// D11
#include <d3d11.h>
#include <d3d11sdklayers.h>
#include <d3dcompiler.h>

//////////////////////////////////////////////////////////////////////////
// 다이렉트11 디바이스

// 렌더 = 스왑체인
class D11Render : public tpl::MemBase
{
public:
	IDXGISwapChain*			_sc;
	ID3D11RenderTargetView*	_rtview;
	ID3D11DepthStencilView*	_dsview;
	ID3D11Texture2D*		_dstex;
	D3D11_VIEWPORT			_vp;

public:
	D11Render();
	~D11Render();

	HRESULT Create(IDXGIFactory* factory, ID3D11Device* device, UINT sacnt, UINT saqlt, kint width, kint height, HWND hwnd, bool windowed);
	HRESULT Layout(ID3D11Device* device, UINT sacnt, UINT saqlt, kint width, kint height);
	void Dispose();

	//
	IDXGISwapChain* GetSc() { return _sc; }
	ID3D11RenderTargetView* GetRtView() { return _rtview; }
	ID3D11DepthStencilView* GetDsView() { return _dsview; }
	ID3D11Texture2D* GetDsTex() { return _dstex; }

	//
	bool Flush();
	void Render(ID3D11DeviceContext* context);
};

// 디바이스
class D11Device : public qgDevice
{
	KCH_SUBCLASS(D11Device, qgDevice);
	KT_DECL_TYPE_INIT(D11Device);
	KT_DECL_TYPE_FINAL(D11Device);
	KCH_FRIEND(D11Shader);
	KCH_FRIEND(D11ShaderWorker);

public:
	// 상태값
	struct Prsn : public qgDevPrsn
	{
		// 재질
		ID3D11PixelShader*		m_shd_ps;
		ID3D11VertexShader*		m_shd_vs;

		// 세이더 프로파일
		char					prof_vs[16];
		char					prof_ps[16];
		char					prof_gs[16];
	};

	// 화면 정보
	struct Screen
	{
		tpl::VecArray<qgScreenDesc>		scr;
		tpl::VecArray<qgAdapterDesc>	adt;
	};

	// 기본 오브젝트
	struct Debz : public qgDevDebz
	{
		qgTexture*				texw;
		qgBuffer*				vb;
		qgLayout*				lo;
		qgShader*				sdraw;
		qgShader*				sglyph;
	};

	// DLL, D11
	static PFN_D3D11_CREATE_DEVICE D3D11CREATEDEVICE;

	// DLL, DCOMPILE
	typedef HRESULT(WINAPI *pD3DReflect)(LPCVOID pSrcData, SIZE_T SrcDataSize, REFIID pInterface, void** ppReflector);
	static pD3DCompile D3DCOMPILE;
	static pD3DReflect D3DREFLECT;

private:
	ID3D11Device*			_device;
	ID3D11DeviceContext*	_context;

	D3D_DRIVER_TYPE		_driver_type;
	D3D_FEATURE_LEVEL	_feature_level;
	UINT				_msaa_count;
	UINT				_msaa_quality;

	D11Render			_render;
	Screen				_screen;

	Prsn				_vprn;
	Debz				_vdeb;

private:
	D11Device();
	~D11Device();

public:
	ID3D11Device* GetDevice() { return _device; }
	ID3D11DeviceContext* GetContext() { return _context; }

	D3D_DRIVER_TYPE GetDriverType() { return _driver_type; }
	D3D_FEATURE_LEVEL GetFeatureLevel() { return _feature_level; }
	UINT GetMsaaCount() { return _msaa_count; }
	UINT GetMsaaQuality() { return _msaa_quality; }
	const char* GetProfileVs() { return _vprn.prof_vs; }
	const char* GetProfilePs() { return _vprn.prof_ps; }
	const char* GetProfileGs() { return _vprn.prof_gs; }

	const Screen& GetScreen() { return _screen; }

public:
	K_OVR bool Layout(const qgSevLayout& e);

	K_OVR bool Enter(kint clearance);
	K_OVR bool Leave();
	K_OVR bool Flush();

	K_OVR void Draw(kint vertexcount, kint vertexstart);
	K_OVR void DrawIndexed(kint indexcount, kint vertexstart);

	K_OVR void DrawRect(const tpl::Rect&bound, const tpl::ColorValue& color, qgTexture* tex, const tpl::Quad* coord);
	K_OVR void DrawGlyph(const tpl::Rect&bound, const tpl::ColorValue& color, qgTexture* tex);
	K_OVR void DrawPolyLine(kint count, const tpl::Point* pts, const tpl::ColorValue* colors);
	K_OVR void DrawPolyStrip(kint count, const tpl::Point* pts, const tpl::ColorValue* colors, qgTexture* tex, const tpl::Vec2* coords);

	K_OVR qgImage* ScreenCapture();

	K_OVR bool _SetRenderTarget(qgTexture* tex);

protected:
	K_OVR bool _Initialize(qgStub* stub, kint flags);
	K_OVR bool _ResetPrepare(const tpl::Point& size, bool prepare);
	K_OVR void _Finalize();

	K_OVR qgBuffer* _RoamImplBuffer(const qgArprBuffer& arpr);
	K_OVR qgLayout* _RoamImplLayout(qgLayoutData* data);
	K_OVR qgTexture* _RoamImplTexture(const qgArprTexture& arpr);
	K_OVR qgTexture* _RoamImplTexture(const qgArprImage& arpr);
	K_OVR qgTexture* _RoamImplMotionTexture(const char* filename, kint flags);
	K_OVR qgDepthBuffer* _RoamImplDepthBuffer(const tpl::Point& size);
	K_OVR qgShader* _RoamImplShader(const char* name);
	K_OVR qgRasz* _RoamImplRasz(const qgRaszData& data);
	K_OVR qgBlnd* _RoamImplBlnd(const qgBlndData& data);
	K_OVR qgSplr* _RoamImplSplr(const qgSplrData& data);

private:
	bool _EnumDisplayMode(IDXGIAdapter* adapter);

	void _InternalTrfmOTM(const tpl::Vec2& size);

	void _InternalDraw(kint texcount, kint vertexcount, kint vertexstart);
	void _InternalDrawIndexed(kint texcount, kint indexcount, kint vertexstart);

	bool _BindMtrl(ksize_t count) throw();
	bool _BindDraw(bool bindindex) throw();
	bool _BindShader() throw();
};

#endif	// __INC_QG_D11_DEV_H__
